package event

import (
	"encoding/json"
)

// 定义请求和响应类型常量，使用小写下划线命名
const (
	get_event                 = "get_event"
	get_events                = "get_events"
	get_processing_events     = "get_processing_events"
	get_current_run_event_ids = "get_current_run_event_ids"
	get_current_run_events    = "get_current_run_events"
	get_current_run_id        = "get_current_run_id"
	get_all_run_ids           = "get_all_run_ids"
	get_all_runs              = "get_all_runs"
	get_event_count           = "get_event_count"
	get_events_for_run        = "get_events_for_run"
	get_all_parents_children  = "get_all_parents_children"

	response_type     = "response"
	event_update_type = "event_update"
	error_type        = "error"
)

const (
	errCodeContentError = iota
	errCodeGetEventFailed
	errCodeUnknownRequest
	errCodeInternalError
)

// 协议基本数据结构
type Frame struct {
	Type  string      `json:"type"`
	Data  interface{} `json:"data"`
	ReqID int         `json:"req_id"`
}

func (f *Frame) Serialize() []byte {
	result, _ := json.Marshal(f)
	return result
}

func (f *Frame) DecodeData(v any) error {
	bs, _ := json.Marshal(f.Data)
	return json.Unmarshal(bs, v)
}

var _reqID int

func nextReqID() int {
	_reqID++
	return _reqID
}

func NewFrame(typ string, data interface{}) *Frame {
	return NewFrameWithReqID(typ, data, nextReqID())
}
func NewFrameWithReqID(typ string, data interface{}, reqID int) *Frame {
	return &Frame{
		Type:  typ,
		Data:  data,
		ReqID: reqID,
	}
}
func DeserializeFrame(data []byte) (*Frame, error) {
	var f Frame
	err := json.Unmarshal(data, &f)
	return &f, err
}

// 封装获取指定ID的事件请求的数据结构
type ReqGetEvent struct {
	ID string `json:"id"`
}

type RepGetEvent struct {
	Event Event `json:"event"`
}

// 封装获取指定ID列表的事件请求的数据结构
type ReqGetEvents struct {
	IDs []string `json:"ids"`
}

type RepGetEvents struct {
	Events []Event `json:"events"`
}

// 封装错误响应的数据结构
type RepError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

type ReqGetEventCount struct {
	RunID string `json:"run_id"`
}

type RepGetEventCount struct {
	Count int64 `json:"count"`
}
type ReqGetEventsForRun struct {
	RunID  string `json:"run_id"`
	Offset int    `json:"offset"`
	Cnt    int    `json:"cnt"`
}

type RepGetAllRuns struct {
	Runs []SoftwareRun `json:"runs"`
}

type RepGetEventsForRun = RepGetEvents

type RepGetProcessingEvents = RepGetEvents
type RepGetCurrentRunEvents = RepGetEvents
type RepGetCurrentRunEventIDs = ReqGetEvents
type RepGetAllRunIDs = ReqGetEvents
type RepEventUpdate = RepGetEvent
type RepGetCurrentRunID = ReqGetEvent

type ReqGetAllParentsChildren = ReqGetEvent
type RepGetAllParentsChildren = RepGetEvents

// 构建各类请求、响应
func NewReqGetEvent(id string) *Frame {
	return NewFrame(get_event, ReqGetEvent{
		ID: id,
	})
}

func NewRepGetEvent(req *Frame, event *Event) *Frame {
	return NewFrameWithReqID(response_type, RepGetEvent{
		Event: *event,
	}, req.ReqID)
}

func NewReqGetEvents(ids []string) *Frame {
	return NewFrame(get_events, ReqGetEvents{
		IDs: ids,
	})
}
func NewRepGetEvents(req *Frame, events []*Event) *Frame {
	es := make([]Event, len(events))
	for i, evt := range events {
		es[i] = *evt
	}
	return NewFrameWithReqID(response_type, RepGetEvents{
		Events: es,
	}, req.ReqID)
}

func NewReqGetProcessingEvents() *Frame {
	return NewFrame(get_processing_events, nil)
}
func NewRepGetProcessingEvents(req *Frame, events []*Event) *Frame {
	evts := make([]Event, len(events))
	for i, evt := range events {
		evts[i] = *evt
	}
	return NewFrameWithReqID(response_type, RepGetProcessingEvents{
		Events: evts,
	}, req.ReqID)
}

func NewReqGetCurrentRunEvents() *Frame {
	return NewFrame(get_current_run_events, nil)
}
func NewRepGetCurrentRunEvents(req *Frame, events []*Event) *Frame {
	evts := make([]Event, len(events))
	for i, evt := range events {
		evts[i] = *evt
	}
	return NewFrameWithReqID(response_type, RepGetCurrentRunEvents{
		Events: evts,
	}, req.ReqID)
}

func NewReqGetCurrentRunEventIds() *Frame {
	return NewFrame(get_current_run_event_ids, nil)
}
func NewRepGetCurrentRunEventIds(req *Frame, ids []string) *Frame {
	return NewFrameWithReqID(response_type, ReqGetEvents{
		IDs: ids,
	}, req.ReqID)
}

func NewReqGetAllRunIds() *Frame {
	return NewFrame(get_all_run_ids, nil)
}
func NewRepGetAllRunIds(req *Frame, ids []string) *Frame {
	return NewFrameWithReqID(response_type, ReqGetEvents{
		IDs: ids,
	}, req.ReqID)
}

func NewReqGetAllRuns() *Frame {
	return NewFrame(get_all_runs, nil)
}

func NewRepGetAllRuns(req *Frame, runs []SoftwareRun) *Frame {
	return NewFrameWithReqID(response_type, RepGetAllRuns{
		Runs: runs,
	}, req.ReqID)
}

func NewReqGetCurrentRunID() *Frame {
	return NewFrame(get_current_run_id, nil)
}
func NewRepGetCurrentRunID(req *Frame, id string) *Frame {
	return NewFrameWithReqID(response_type, RepGetCurrentRunID{ID: id}, req.ReqID)
}

func NewRepError(req *Frame, code int, message string) *Frame {
	return NewFrameWithReqID(error_type, RepError{
		Code:    code,
		Message: message,
	}, req.ReqID)
}

func NewRepEventUpdate(event *Event) *Frame {
	return NewFrameWithReqID(event_update_type, RepEventUpdate{
		Event: *event,
	}, 0)
}

func NewReqGetEventCount(runID string) *Frame {
	return NewFrame(get_event_count, ReqGetEventCount{
		RunID: runID,
	})
}

func NewRepGetEventCount(req *Frame, count int64) *Frame {
	return NewFrameWithReqID(response_type, RepGetEventCount{
		Count: count,
	}, req.ReqID)
}

func NewReqGetEventsForRun(runID string, offset int, cnt int) *Frame {
	return NewFrame(get_events_for_run, ReqGetEventsForRun{
		RunID:  runID,
		Offset: offset,
		Cnt:    cnt,
	})
}

func NewRepGetEventsForRun(req *Frame, events []*Event) *Frame {
	es := make([]Event, len(events))
	for i, evt := range events {
		es[i] = *evt
	}
	return NewFrameWithReqID(response_type, RepGetEventsForRun{
		Events: es,
	}, req.ReqID)
}

func NewReqGetAllParentsChildren(id string) *Frame {
	return NewFrame(get_all_parents_children, ReqGetAllParentsChildren{
		ID: id,
	})
}

func NewRepGetAllParentsChildren(req *Frame, events []Event) *Frame {
	return NewFrameWithReqID(response_type, RepGetAllParentsChildren{
		Events: events,
	}, req.ReqID)
}
